import React, {useEffect, useRef} from 'react';

const lerp = (a, b, n) => (1 - n) * a + n * b;
const map = (x, a, b, c, d) => (x - a) * (d - c) / (b - a) + c;

const useWindowSize = () => {
    const [size, setSize] = React.useState({width: window.innerWidth, height: window.innerHeight});

    useEffect(() => {
        const handleResize = () => {
            setSize({width: window.innerWidth, height: window.innerHeight});
        };
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
    }, []);

    return size;
};

const ImageTrail = ({
                        imageUrl = '',
                        totalTrailElements = 5,
                        perspective = false,
                        opacityChange = false,
                        valuesFromTo = {x: [-90, 90], y: [-90, 90], rx: [0, 0], ry: [0, 0], rz: [0, 0]},
                        amt = pos => 0.02 * pos + 0.05,
                        amtMain = ''
                    }) => {
    const containerRef = useRef(null);
    const imageRefs = useRef([]);
    const transforms = useRef([...Array(totalTrailElements)].map(() => ({x: 0, y: 0, rx: 0, ry: 0, rz: 0})));
    const cursor = useRef({x: window.innerWidth / 2, y: window.innerHeight / 2});
    const winsize = useWindowSize();

    useEffect(() => {
        const handleMouseMove = e => {
            cursor.current = {x: e.clientX, y: e.clientY};
        };

        window.addEventListener('mousemove', handleMouseMove);

        const render = () => {
            for (let i = 0; i < totalTrailElements; i++) {
                const amtVal = i < totalTrailElements - 1 ? amt(i) : amtMain ?? amt(totalTrailElements - 1);
                const transform = transforms.current[i];

                transform.x = lerp(transform.x, map(cursor.current.x, 0, winsize.width, valuesFromTo.x[0], valuesFromTo.x[1]), amtVal);
                transform.y = lerp(transform.y, map(cursor.current.y, 0, winsize.height, valuesFromTo.y[0], valuesFromTo.y[1]), amtVal);
                transform.rx = perspective ? lerp(transform.rx, map(cursor.current.y, 0, winsize.height, valuesFromTo.rx[0], valuesFromTo.rx[1]), amtVal) : 0;
                transform.ry = perspective ? lerp(transform.ry, map(cursor.current.x, 0, winsize.width, valuesFromTo.ry[0], valuesFromTo.ry[1]), amtVal) : 0;
                transform.rz = lerp(transform.rz, map(cursor.current.x, 0, winsize.width, valuesFromTo.rz[0], valuesFromTo.rz[1]), amtVal);

                const el = imageRefs.current[i];
                if (el) {
                    el.style.transform = `translateX(${transform.x}px) translateY(${transform.y}px) rotateX(${transform.rx}deg) rotateY(${transform.ry}deg) rotateZ(${transform.rz}deg)`;
                }
            }
            requestAnimationFrame(render);
        };

        requestAnimationFrame(render);
        return () => window.removeEventListener('mousemove', handleMouseMove);
    }, [amt, amtMain, totalTrailElements, valuesFromTo, winsize, perspective]);

    return (
        <div
            ref={containerRef}
            style={{
                display: 'grid',
                placeItems: 'center',
                position: 'relative',
                width: '100%',
                height: '100vh',
                perspective: perspective ? `${perspective}px` : 'none'
            }}
        >
            {[...Array(totalTrailElements)].map((_, i) => (
                <img
                    key={i}
                    ref={el => (imageRefs.current[i] = el)}
                    src={imageUrl}
                    alt="trail"
                    style={{
                        position: 'absolute',
                        opacity: opacityChange ? (i === totalTrailElements - 1 ? 1 : (1 / totalTrailElements) * i + 1 / totalTrailElements) : 1,
                        maxHeight: '45vh',
                        willChange: 'transform',
                        gridArea: '1 / 1 / 2 / 2'
                    }}
                />
            ))}
        </div>
    );
};

export default ImageTrail;